#include "baserenderer.h"
#include "renderer.h"

BaseRenderer::BaseRenderer(OverlayState const* pState)
  : state(pState)
  , tFrame(NULL)
  , tReply(NULL)
  , tScroll(NULL)
  , tImages(NULL)
  , numImages(8)
{
  tImages = new BaseTexture*[numImages];
  memset(tImages, 0, sizeof(BaseTexture*) * numImages);
}

void BaseRenderer::reset()
{
  delete tFrame;
  delete tReply;
  delete tScroll;
  for (int i = 0; i < numImages; i++)
    delete tImages[i];
  tFrame = NULL;
  tReply = NULL;
  tScroll = NULL;
  memset(tImages, 0, sizeof(BaseTexture*) * numImages);
}

BaseRenderer::~BaseRenderer()
{
  delete tFrame;
  delete tReply;
  delete tScroll;
  for (int i = 0; i < numImages; i++)
    delete tImages[i];
  delete[] tImages;
}

bool BaseRenderer::getTexture(BaseTexture** tex, ImageHeader* image)
{
  if (*tex == NULL)
    *tex = newTexture();
  return updateTexture(*tex, image);
}
void BaseRenderer::render()
{
  SharedData::Lock lock(state->data, 100);
  if (!lock.locked())
    return;
  SharedHeader* hdr = state->data->header();
  if (hdr->hidden)
    return;

  setViewport(hdr->left, hdr->top, hdr->right, hdr->bottom);

  FrameHeader* frame = state->data->frame();
  if (getTexture(&tFrame, frame))
    drawRect(tFrame, hdr->left, hdr->top, hdr->right, hdr->bottom);

  int replyHeight = 0;
  ReplyHeader* reply = state->data->reply();
  if ((state->showReply || state->hoverReply) && reply->width && reply->height)
  {
    replyHeight += reply->height - 2;
    if (getTexture(&tReply, reply))
    {
      int y = hdr->bottom - reply->height * (hdr->bottom - hdr->top) / frame->height;
      drawRect(tReply, hdr->left, y, hdr->right, hdr->bottom);
      if ((GetTickCount() % 1000) < 500)
      {
        int cx = hdr->left + hdr->replyPos[hdr->replyCaret] * (hdr->right - hdr->left) / frame->width;
        int ch = 18 * (hdr->bottom - hdr->top) / frame->height;
        drawRect(NULL, cx, (y + hdr->bottom - ch) / 2, cx + 1, (y + hdr->bottom + ch) / 2);
      }
    }
  }

  ScrollHeader* scroll = state->data->scroll();
  if (scroll->width && scroll->height && hdr->maxScroll >= 0 && getTexture(&tScroll, scroll))
  {
    int height = frame->height - scroll->barTop - scroll->barBottom - replyHeight;
    int content = frame->height - frame->insetTop - frame->insetBottom - replyHeight;
    int maxScroll = hdr->maxScroll + content;
    int barHeight = height * content / maxScroll;
    int barOffset = height * hdr->scrollPos / maxScroll;
    RECT src;
    src.left = frame->width - scroll->barRight - scroll->width;
    src.right = frame->width - scroll->barRight;
    src.top = scroll->barTop + barOffset;
    src.bottom = src.top + barHeight;
    src.left = hdr->left + src.left * (hdr->right - hdr->left) / frame->width;
    src.top = hdr->top + src.top * (hdr->bottom - hdr->top) / frame->height;
    src.right = hdr->left + src.right * (hdr->right - hdr->left) / frame->width;
    src.bottom = hdr->top + src.bottom * (hdr->bottom - hdr->top) / frame->height;
    drawRect(tScroll, src.left, src.top, src.right, src.bottom,
      state->display & DISPLAY_SCROLL ? 0xFFFFFFFF : 0x99FFFFFF);
  }

  setViewport(hdr->left + frame->insetLeft * (hdr->right - hdr->left) / frame->width,
              hdr->top + frame->insetTop * (hdr->bottom - hdr->top) / frame->height,
              hdr->right - frame->insetRight * (hdr->right - hdr->left) / frame->width,
              hdr->bottom - (frame->insetBottom + replyHeight) * (hdr->bottom - hdr->top) / frame->height + 8);

  while (hdr->numLines > numImages)
  {
    BaseTexture** tmp = new BaseTexture*[numImages * 2];
    memcpy(tmp, tImages, sizeof(BaseTexture*) * numImages);
    memset(tmp + numImages, 0, sizeof(BaseTexture*) * numImages);
    delete[] tImages;
    tImages = tmp;
    numImages *= 2;
  }

  int y0 = frame->insetTop;
  int y1 = frame->height - frame->insetBottom - replyHeight;
  int x0 = frame->insetLeft;
  int y = y0 - hdr->scrollPos - replyHeight;
  for (int i = 0; i < hdr->numLines; i++)
  {
    LineHeader* line = state->data->line(i);
    if (line->updated < 0 && i - line->updated < numImages)
    {
      BaseTexture* tmp = tImages[i];
      tImages[i] = tImages[i - line->updated];
      tImages[i - line->updated] = tmp;
      line->updated = 0;
    }
    else if (line->updated < 0)
      line->updated = 1;
    y += line->insetTop;
    int top = 0;
    int bottom = line->height;
    if (y + top < y0) top = y0 - y;
    if (y + bottom > y1) bottom = y1 - y;
    if (y < y1 && y + line->height > y0 && getTexture(&tImages[i], line))
    {
      drawRect(tImages[i],
        hdr->left + x0 * (hdr->right - hdr->left) / frame->width,
        hdr->top + y * (hdr->bottom - hdr->top) / frame->height,
        hdr->left + (x0 + line->width) * (hdr->right - hdr->left) / frame->width,
        hdr->top + (y + line->height) * (hdr->bottom - hdr->top) / frame->height);
    }
    y += line->height + line->insetBottom;
  }
}
